//
//  StatisticsController.swift
//  hello
//
//  Created by 赵康 on 2024/12/21.
//

import Vapor
import Fluent
import Redis

struct StatisticsController: RouteCollection {
	func boot(routes: any RoutesBuilder) throws {
		let statistics = routes.grouped("\(RouteEnum.statistics.rawValue)")
		let protected = statistics.grouped(AuthMiddleware())
		protected.get("\(RouteEnum.daily.rawValue)", use: getDailyStatistics)
		protected.get("\(RouteEnum.ranking.rawValue)", use: getRankingList)
		protected
			.get("\(RouteEnum.ranking.rawValue)", "\(RouteEnum.me.rawValue)", use: getMyRanking)
		protected.get("\(RouteEnum.overview.rawValue)", use: getOverview)
    protected
      .get(
        "\(RouteEnum.recent7DaysAudios.rawValue)",
        use: getRecent7DaysAudiosCount
      )
    protected
      .get(
        "\(RouteEnum.tagsDistribution.rawValue)",
        use: getTagsDistribution
      )
	}
	struct TimeRangeQuery: Content {
		var range: String
		var tagID: String?
		
		func toTimeRange() throws -> TimeRange {
			guard let timeRange = TimeRange.fromRedisKey(range) else {
				throw Abort(.badRequest, reason: "Invalid time range format")
			}
			return timeRange
		}

		func getTagID() -> UUID? {
			guard let tagIDString = tagID else { return nil }
			return UUID(uuidString: tagIDString)
		}
	}
	struct StatisticsOverviewResponse: Content {
		let statistics: [StatisticsService.StatisticsResponse]  // 改用原始数据模型
		let totalDuration: Double        // 改用原始数值
		let timeRange: String
	}
	private func formatLocalDate(_ date: Date) -> String {
		let formatter = DateFormatter()
		formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
		formatter.timeZone = Calendar.current.timeZone
		return formatter.string(from: date)
	}
		// 2. 修改控制器函数
	@Sendable
	func getDailyStatistics(req: Request) async throws -> StatisticsOverviewResponse {
		// 1. 获取用户 ID
		let userID = try req.authenticatedUserID
		
		// 2. 尝试解析查询参数
		let query = try req.query.decode(TimeRangeQuery.self)
		
		// 3. 转换时间范围
		let timeRange = try query.toTimeRange()
		let (_, _) = timeRange.getDateRange()
		
		// 4. 获取统计数据（使用未格式化的数据）
		let statistics = try await req.application.statistics
			.getUserStatistics(
				userID: userID,
				timeRange: timeRange,
				tagID: query.getTagID()
			)
		// 5. 计算总时长（只返回原始数值）
		let totalDuration = statistics.reduce(0.0) { $0 + $1.duration }
		 
		return StatisticsOverviewResponse(
			statistics: statistics,
			totalDuration: totalDuration,
			timeRange: query.range
		)
	}

	@Sendable
	func getRankingList(req: Request) async throws -> [StatisticsService.RankingResponse] {
		// 1. 解析时间范围查询参数
		let query = try req.query.decode(TimeRangeQuery.self)
		
		// 2. 转换时间范围
		let timeRange = try query.toTimeRange()
		
		// 3. 获取并验证 limit 参数
		let limit = (try? req.query.get(Int.self, at: "limit")) ?? 100
		guard limit > 0 && limit <= 1000 else {
			throw Abort(.badRequest, reason: "Limit must be between 1 and 1000")
		}
		
		// 4. 获取排行榜数据
		let rankings = try await req.application.statistics.getRankingList(
			timeRange: timeRange,
			tagID: query.getTagID(),
			limit: limit
		)
		
		return rankings
	}
	
	@Sendable
	func getMyRanking(req: Request) async throws -> StatisticsService.RankingResponse? {
		// 1. 获取用户 ID
		let userID = try req.authenticatedUserID
		
		// 2. 解析时间范围查询参数
		let query = try req.query.decode(TimeRangeQuery.self)
		
		// 3. 转换时间范围
		let timeRange = try query.toTimeRange()
		
		// 4. 获取个人排名数据
		let ranking = try await req.application.statistics.getUserRanking(
			userID: userID,
			timeRange: timeRange,
			tagID: query.getTagID()
		)
		
		return ranking
	}
	@Sendable
	func getOverview(req: Request) async throws -> OverviewResponse {
		let userID = try req.authenticatedUserID
		let tagID = try? req.query.get(UUID.self, at: "tagID")
		
		// 使用新方法获取各时间段的总时长
		async let todayDuration = req.application.statistics.getUserTotalDuration(
			userID: userID,
			timeRange: .day,
			tagID: tagID
		)
		async let weekDuration = req.application.statistics.getUserTotalDuration(
			userID: userID,
			timeRange: .week,
			tagID: tagID
		)
		async let monthDuration = req.application.statistics.getUserTotalDuration(
			userID: userID,
			timeRange: .month,
			tagID: tagID
		)
		async let yearDuration = req.application.statistics.getUserTotalDuration(
			userID: userID,
			timeRange: .year,
			tagID: tagID
		)
		
		// 并发获取排名数据
		async let todayRanking = req.application.statistics.getUserStatisticsRanking(
			userID: userID,
			timeRange: .day,
			tagID: tagID
		)
		async let weekRanking = req.application.statistics.getUserStatisticsRanking(
			userID: userID,
			timeRange: .week,
			tagID: tagID
		)
		async let monthRanking = req.application.statistics.getUserStatisticsRanking(
			userID: userID,
			timeRange: .month,
			tagID: tagID
		)
		async let yearRanking = req.application.statistics.getUserStatisticsRanking(
			userID: userID,
			timeRange: .year,
			tagID: tagID
		)
		
		let (today, week, month, year, todayRank, weekRank, monthRank, yearRank) =
		try await (todayDuration, weekDuration, monthDuration, yearDuration,
							 todayRanking, weekRanking, monthRanking, yearRanking)
		
		// 计算超过百分比的辅助函数
		let calculateExceedPercentage = { (ranking: (rank: Int, totalUsers: Int)?) -> Double in
			guard let ranking = ranking, ranking.totalUsers > 0 else { return 0 }
			let exceededUsers = ranking.totalUsers - ranking.rank
			return Double(exceededUsers) / Double(ranking.totalUsers) * 100
		}
		
		// 构建返回数据
		return OverviewResponse(
			today: .init(
				totalDuration: today,
				timeRange: "today",
				exceedPercentage: calculateExceedPercentage(todayRank)
			),
			week: .init(
				totalDuration: week,
				timeRange: "week",
				exceedPercentage: calculateExceedPercentage(weekRank)
			),
			month: .init(
				totalDuration: month,
				timeRange: "month",
				exceedPercentage: calculateExceedPercentage(monthRank)
			),
			year: .init(
				totalDuration: year,
				timeRange: "year",
				exceedPercentage: calculateExceedPercentage(yearRank)
			)
		)
	}

	@Sendable
	func getRecent7DaysAudiosCount(req: Request) async throws -> Recent7DaysAudiosCountResponse {
		let userID = try req.authenticatedUserID
		
		// 获取最近7天的音频统计
		let result = try await req.application.statistics.getUserRecentAudiosStats(userID: userID)
		
		return Recent7DaysAudiosCountResponse(
			audioCount: result.count,
			exceedPercentage: result.exceedPercentage
		)
	}

	@Sendable
	func getTagsDistribution(req: Request) async throws -> TagDistributionResponse {
		let userID = try req.authenticatedUserID
		
		// 获取最近7天标签分布数据
		let distribution = try await req.application.statistics.getTagsDistribution(userID: userID)
		
		return distribution
	}
}

struct OverviewResponse: Content {
	let today: Summary
	let week: Summary
	let month: Summary
	let year: Summary
	struct Summary: Content {
		let totalDuration: Double
		let formattedDuration: String
		let timeRange: String
		let exceedPercentage: Double
		
		init(totalDuration: Double, timeRange: String, exceedPercentage: Double) {
			self.totalDuration = totalDuration
			self.formattedDuration = Self.formatDuration(totalDuration)
			self.timeRange = timeRange
			self.exceedPercentage = exceedPercentage
		}
		var formattedExceedPercentage: String {
			String(format: "%.1f%%", exceedPercentage)
		}
			// 将格式化方法移到 Summary 内部
		private static func formatDuration(_ duration: Double) -> String {
			// 使用DateComponents而不是直接计算
			let components = DateComponents(
				hour: Int(duration) / 3600,
				minute: (Int(duration) % 3600) / 60,
				second: Int(duration) % 60
			)
			
			if components.hour! > 0 {
				if components.minute! > 0 {
					return "\(components.hour!)小时\(components.minute!)分钟"
				} else {
					return "\(components.hour!)小时"
				}
			} else if components.minute! > 0 {
				if components.second! > 0 {
					return "\(components.minute!)分\(components.second!)秒"
				} else {
					return "\(components.minute!)分钟"
				}
			} else {
				return "\(components.second!)秒"
			}
		}
	}
}

struct TagDistributionResponse: Content {
	let totalDuration: Double
	let tags: [TagDistribution]
	
	struct TagDistribution: Content {
		let id: UUID
		let name: String
		let duration: Double
		let percentage: Double
	}
}

extension Optional: @retroactive AsyncResponseEncodable where Wrapped: AsyncResponseEncodable {
	public func encodeResponse(for request: Request) async throws -> Response {
		switch self {
			case .some(let value):
				return try await value.encodeResponse(for: request)
			case .none:
				return Response(status: .noContent)
		}
	}
}
